www.gusucode.com > VC++仿XP免费Prof UIS界面库-源码程序 > VC++仿XP免费Prof UIS界面库-源码程序/code/Src/ExtHook.cpp

    //Download by http://www.NewXing.com
// This is part of the Professional User Interface Suite library.
// Copyright (C) 2001-2004 FOSS Software, Inc.
// All rights reserved.
//
// http://www.prof-uis.com
// http://www.fossware.com
// mailto:foss@fossware.com
//
// This source code can be used, modified and redistributed
// under the terms of the license agreement that is included
// in the Professional User Interface Suite package.
//
// Warranties and Disclaimers:
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND
// INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
// IN NO EVENT WILL FOSS SOFTWARE INC. BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES,
// INCLUDING DAMAGES FOR LOSS OF PROFITS, LOSS OR INACCURACY OF DATA,
// INCURRED BY ANY PERSON FROM SUCH PERSON'S USAGE OF THIS SOFTWARE
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

#include "StdAfx.h"

#if (!defined __EXT_HOOK_H)
	#include "ExtHook.h"
#endif

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

struct __PROF_UIS_API CExtHookSink::HookSinkArray_t :
	public CArray< CExtHookSink *, CExtHookSink * >
{
	INT Find( const CExtHookSink * pHookSink ) const
	{
		ASSERT( pHookSink != NULL );
		for( INT nSinkIdx = 0; nSinkIdx < GetSize(); nSinkIdx++ )
		{
			const CExtHookSink * pHookSinkExamine =
				GetAt( nSinkIdx );
			ASSERT( pHookSink != NULL );
			if( pHookSinkExamine == pHookSink )
				return nSinkIdx;
		}
		return -1;
	}
	void AddHead( CExtHookSink * pHookSink )
	{
		ASSERT( pHookSink != NULL );
		InsertAt( 0, pHookSink );
	}
	void AddTail( CExtHookSink * pHookSink )
	{
		ASSERT( pHookSink != NULL );
		InsertAt( GetSize(), pHookSink );
	}
}; // struct HookSinkArray_t

struct __PROF_UIS_API CExtHookSink::HookChains_t
{
	HookSinkArray_t m_HookSinkArray;
	HWND m_hWndHooked;
	WNDPROC m_pWNDPROC;

	static LRESULT CALLBACK g_HookWndProc(
		HWND hWnd,
		UINT nMessage,
		WPARAM wParam,
		LPARAM lParam
		);

	HookChains_t(
		HWND hWndHooked
		)
		: m_hWndHooked( hWndHooked )
	{
		ASSERT( m_hWndHooked != NULL );
		ASSERT( ::IsWindow(m_hWndHooked) );

		m_pWNDPROC = (WNDPROC)
			::SetWindowLong(
				m_hWndHooked,
				GWL_WNDPROC,
				(DWORD)g_HookWndProc
				);
		ASSERT( m_pWNDPROC != NULL );
	};

	~HookChains_t()
	{
		DestroyChains( false );
	};

	void DestroyChains( bool bDelete )
	{
		for( int nSinkIdx=0; nSinkIdx < m_HookSinkArray.GetSize(); nSinkIdx++ )
		{
			CExtHookSink * pHookSink =
				m_HookSinkArray[ nSinkIdx ];
			ASSERT( pHookSink != NULL );
			if( pHookSink->IsAutoDeleteHookWndSink() )
				delete pHookSink;
		} // for( int nSinkIdx=0; nSinkIdx < m_HookSinkArray.GetSize(); nSinkIdx++ )
		m_HookSinkArray.RemoveAll();

		ASSERT( m_hWndHooked != NULL );
		ASSERT( ::IsWindow(m_hWndHooked) );
		ASSERT( m_pWNDPROC != NULL );

		::SetWindowLong(
			m_hWndHooked,
			GWL_WNDPROC,
			(DWORD)m_pWNDPROC
			);

		if( bDelete )
			delete this;
	};

	LRESULT HookChainsWindowProc(
		UINT nMessage,
		WPARAM & wParam,
		LPARAM & lParam
		)
	{
		ASSERT( m_hWndHooked != NULL );
		ASSERT( ::IsWindow(m_hWndHooked) );
		ASSERT( m_pWNDPROC != NULL );
		for( int nSinkIdx=0; nSinkIdx < m_HookSinkArray.GetSize(); nSinkIdx++ )
		{
			CExtHookSink * pHookSink =
				m_HookSinkArray[ nSinkIdx ];
			ASSERT( pHookSink != NULL );
			if( nMessage == WM_NCDESTROY ) 
			{
				pHookSink->OnHookWndNcDestroy();
				continue;
			}
			LRESULT lResult = 0;
			if(	pHookSink->OnHookWndMsg(
					lResult,
					m_hWndHooked,
					nMessage,
					wParam,
					lParam
					)
				)
				return lResult;
		} // for( int nSinkIdx=0; nSinkIdx < m_HookSinkArray.GetSize(); nSinkIdx++ )
		WNDPROC pWNDPROC = m_pWNDPROC;
		HWND hWndHooked = m_hWndHooked;
		if( nMessage == WM_NCDESTROY ) 
			DestroyChains( true );
		LRESULT lResult =
			::CallWindowProc(
				pWNDPROC,
				hWndHooked,
				nMessage,
				wParam,
				lParam
				);
		return lResult;
	};

}; // struct CExtHookSink::HookChains_t

typedef
	CMap < HWND, HWND,
		CExtHookSink::HookChains_t *, CExtHookSink::HookChains_t * >
	HookChainsMap_t;

static HookChainsMap_t g_HookChainsMap;

LRESULT CALLBACK CExtHookSink::HookChains_t::g_HookWndProc(
	HWND hWnd,
	UINT nMessage,
	WPARAM wParam,
	LPARAM lParam
	)
{
#ifdef _USRDLL
	// If this is a DLL, need to set up MFC state
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif

LRESULT lResult = 0;

MSG & refMsgMfcCurr = AfxGetThreadState()->m_lastSentMsg;
MSG msgMfcSaved( refMsgMfcCurr );
	refMsgMfcCurr.hwnd    = hWnd;
	refMsgMfcCurr.message = nMessage;
	refMsgMfcCurr.wParam  = wParam;
	refMsgMfcCurr.lParam  = lParam;

CExtHookSink::HookChains_t * pHookChains = NULL;
	if( g_HookChainsMap.Lookup( hWnd, pHookChains ) )
	{
		ASSERT( pHookChains != NULL );
		ASSERT( pHookChains->m_hWndHooked == hWnd );
		lResult =
			pHookChains->HookChainsWindowProc(
				nMessage,
				wParam,
				lParam
				);  
		if( nMessage == WM_NCDESTROY ) 
			g_HookChainsMap.RemoveKey( hWnd );
	} // if( g_HookChainsMap.Lookup( hWnd, pHookChains ) )

	refMsgMfcCurr = msgMfcSaved;
	
	return lResult;
}

CExtHookSink::CExtHookSink(
	bool bEnableDetailedWndHooks // = true
	)
	: m_bEnableDetailedWndHooks( bEnableDetailedWndHooks )
{
}

CExtHookSink::~CExtHookSink()
{
}

LRESULT CExtHookSink::OnHookWndMsgNextProcInvoke(
	UINT nMessage,
	WPARAM wParam,
	LPARAM lParam
	)
{
MSG & msgCurrMfc = AfxGetThreadState()->m_lastSentMsg;
	ASSERT( msgCurrMfc.hwnd != NULL );
	ASSERT( ::IsWindow( msgCurrMfc.hwnd ) );

CExtHookSink::HookChains_t * pHookChains = NULL;
	VERIFY(
		g_HookChainsMap.Lookup(
			msgCurrMfc.hwnd,
			pHookChains
			)
		);
	ASSERT( pHookChains != NULL );
	ASSERT( pHookChains->m_hWndHooked == msgCurrMfc.hwnd );
	ASSERT( pHookChains->m_pWNDPROC != NULL );

	return
		::CallWindowProc(
			pHookChains->m_pWNDPROC,
			msgCurrMfc.hwnd,
			nMessage,
			wParam,
			lParam
			);
}

LRESULT CExtHookSink::OnHookWndMsgNextProcCurrent(
	WPARAM wParam,
	LPARAM lParam
	)
{
MSG & msgCurrMfc = AfxGetThreadState()->m_lastSentMsg;
	ASSERT( msgCurrMfc.hwnd != NULL );
	ASSERT( ::IsWindow( msgCurrMfc.hwnd ) );

CExtHookSink::HookChains_t * pHookChains = NULL;
	VERIFY(
		g_HookChainsMap.Lookup(
			msgCurrMfc.hwnd,
			pHookChains
			)
		);
	ASSERT( pHookChains != NULL );
	ASSERT( pHookChains->m_hWndHooked == msgCurrMfc.hwnd );
	ASSERT( pHookChains->m_pWNDPROC != NULL );

	return
		::CallWindowProc(
			pHookChains->m_pWNDPROC,
			msgCurrMfc.hwnd,
			msgCurrMfc.message,
			wParam,
			lParam
			);
}

LRESULT CExtHookSink::OnHookWndMsgDefault()
{
MSG & msgCurrMfc = AfxGetThreadState()->m_lastSentMsg;
	ASSERT( msgCurrMfc.hwnd != NULL );
	ASSERT( ::IsWindow( msgCurrMfc.hwnd ) );

CExtHookSink::HookChains_t * pHookChains = NULL;
	VERIFY(
		g_HookChainsMap.Lookup(
			msgCurrMfc.hwnd,
			pHookChains
			)
		);
	ASSERT( pHookChains != NULL );
	ASSERT( pHookChains->m_hWndHooked == msgCurrMfc.hwnd );
	ASSERT( pHookChains->m_pWNDPROC != NULL );

	return
		::CallWindowProc(
			pHookChains->m_pWNDPROC,
			msgCurrMfc.hwnd,
			msgCurrMfc.message,
			msgCurrMfc.wParam,
			msgCurrMfc.lParam
			);
}

bool CExtHookSink::OnHookWndMsg(
	LRESULT & lResult,
	HWND hWndHooked,
	UINT nMessage,
	WPARAM & wParam,
	LPARAM & lParam
	)
{
	lResult;
	hWndHooked;
	nMessage;
	wParam;
	lParam;

	if( !m_bEnableDetailedWndHooks )
		return false;

	switch( nMessage )
	{
	case WM_COMMAND:
		return
			OnHookCmdMsg(
				lResult,
				hWndHooked,
				HIWORD(wParam),
				LOWORD(wParam),
				(HWND)lParam
				);
	case WM_NOTIFY:
		return
			OnHookNotifyMsg(
				lResult,
				hWndHooked,
				(INT)wParam,
				(LPNMHDR)lParam
				);
	case WM_PAINT:
		return
			OnHookPaintMsg(
				lResult,
				hWndHooked,
				(HDC)wParam
				);
	case WM_ERASEBKGND:
		return
			OnHookEraseBackgroundMsg(
				lResult,
				hWndHooked,
				(HDC)wParam
				);
	case WM_PRINT:
		return
			OnHookPrintMsg(
				lResult,
				hWndHooked,
				(HDC)wParam
				);
	case WM_NCPAINT:
		return
			OnHookNcPaintMsg(
				lResult,
				hWndHooked,
				(HRGN)wParam
				);
	} // switch( nMessage )

	return false;
}

bool CExtHookSink::OnHookCmdMsg(
	LRESULT & lResult,
	HWND hWndHooked,
	WORD wNotifyCode,
	WORD wID,
	HWND hWndCtrl
	)
{
	lResult;
	hWndHooked;
	wNotifyCode;
	wID;
	hWndCtrl;
	
	return false;
}

bool CExtHookSink::OnHookNotifyMsg(
	LRESULT & lResult,
	HWND hWndHooked,
	INT nIdCtrl,
	LPNMHDR lpnmhdr
	)
{
	lResult;
	hWndHooked;
	nIdCtrl;
	lpnmhdr;
	
	return false;
}

bool CExtHookSink::OnHookPaintMsg(
	LRESULT & lResult,
	HWND hWndHooked,
	HDC hDC
	)
{
	lResult;
	hWndHooked;
	hDC;
	
	return false;
}

bool CExtHookSink::OnHookEraseBackgroundMsg(
	LRESULT & lResult,
	HWND hWndHooked,
	HDC hDC
	)
{
	lResult;
	hWndHooked;
	hDC;
	
	return false;
}

bool CExtHookSink::OnHookPrintMsg(
	LRESULT & lResult,
	HWND hWndHooked,
	HDC hDC
	)
{
	lResult;
	hWndHooked;
	hDC;
	
	return false;
}

bool CExtHookSink::OnHookNcPaintMsg(
	LRESULT & lResult,
	HWND hWndHooked,
	HRGN hRgnUpdate
	)
{
	lResult;
	hWndHooked;
	hRgnUpdate;
	
	return false;
}

void CExtHookSink::OnHookWndNcDestroy()
{
}

void CExtHookSink::OnHookWndAttach( HWND hWnd )
{
	ASSERT( hWnd != NULL );
	hWnd;
}

void CExtHookSink::OnHookWndDetach( HWND hWnd )
{
	ASSERT( hWnd != NULL );
	hWnd;
}

bool CExtHookSink::IsAutoDeleteHookWndSink()
{
	return false;
}

bool CExtHookSink::SetupHookWndSink(
	HWND hWnd,
	bool bRemove, // = false
	bool bAddToHead // = false
	)
{
	ASSERT( hWnd != NULL );
	if( hWnd == NULL )
		return false;

	ASSERT( bRemove || (!bRemove && ::IsWindow(hWnd)) );
	if( (!bRemove) && (!::IsWindow(hWnd) ) )
		return false;

CExtHookSink::HookChains_t * pHookChains = NULL;
	if( !g_HookChainsMap.Lookup( hWnd, pHookChains ) )
	{
		ASSERT( pHookChains == NULL );
	}
	else
	{
		ASSERT( pHookChains != NULL );
	}
	
	if( bRemove )
	{
		if( pHookChains == NULL )
			return true;
		INT pos =
			pHookChains->m_HookSinkArray.Find( this );
		if( pos < 0 )
			return true;

		OnHookWndDetach( hWnd );

		pHookChains->m_HookSinkArray.RemoveAt( pos );
		if( IsAutoDeleteHookWndSink() )
			delete this;
		
		//if( pHookChains->m_HookSinkArray.GetSize() == 0 )
		//	pHookChains->DestroyChains( true );

		return true;
	} // if( bRemove )
	
	if( pHookChains == NULL )
	{
		pHookChains =
			new CExtHookSink::HookChains_t( hWnd );
		g_HookChainsMap.SetAt( hWnd, pHookChains );
	} // if( pHookChains == NULL )
	else
	{
		INT pos =
			pHookChains->m_HookSinkArray.Find( this );
		if( pos >= 0 )
			return true;
	} // else from if( pHookChains == NULL )

	if( bAddToHead )
		pHookChains->m_HookSinkArray.AddHead( this );
	else
		pHookChains->m_HookSinkArray.AddTail( this );

	OnHookWndAttach( hWnd );

	return true;
}

ULONG CExtHookSink::SetupHookWndSinkToChilds(
	HWND hWnd,
	UINT * pDlgCtrlIDs, // = NULL
	ULONG nCountOfDlgCtrlIDs, // = 0
	bool bDeep // = false
	)
{
	ASSERT( hWnd != NULL );
	if( hWnd == NULL )
		return 0;

	ASSERT( ::IsWindow(hWnd) );
	if( !::IsWindow(hWnd) )
		return 0;
ULONG nCountOfHooks = 0;
	hWnd = ::GetWindow( hWnd, GW_CHILD );
	for( ; hWnd != NULL; hWnd = ::GetWindow( hWnd, GW_HWNDNEXT ) )
	{
		ASSERT(
			(nCountOfDlgCtrlIDs == 0 && pDlgCtrlIDs == NULL)
			|| (nCountOfDlgCtrlIDs > 0 && pDlgCtrlIDs != NULL)
			);
		bool bSetupHook = true;
		if( nCountOfDlgCtrlIDs > 0 && pDlgCtrlIDs != NULL )
		{
			bSetupHook = false;
			UINT nDlgCtrlID = ::GetDlgCtrlID( hWnd );
			for( ULONG i=0; i<nCountOfDlgCtrlIDs; i++ )
			{
				if( pDlgCtrlIDs[i] == nDlgCtrlID )
				{
					bSetupHook = true;
					break;
				}
			} // for( ULONG i=0; i<nCountOfDlgCtrlIDs; i++ )
		} // if( nCountOfDlgCtrlIDs > 0 && pDlgCtrlIDs != NULL )
		if( bSetupHook )
		{
			if(	SetupHookWndSink( hWnd ) )
				nCountOfHooks++;
			else
			{
				ASSERT( FALSE );
			}
		} // if( bSetupHook )
		if( bDeep )
			nCountOfHooks +=
				SetupHookWndSinkToChilds(
					hWnd,
					pDlgCtrlIDs,
					nCountOfDlgCtrlIDs,
					bDeep
					);
	} // for( ; hWnd != NULL; hWnd = ::GetWindow( hWnd, GW_HWNDNEXT ) )
	return nCountOfHooks;
}

void CExtHookSink::RemoveAllWndHooks()
{
HookedWndList_t _list;
	GetHookedWindows( _list );
POSITION pos = _list.GetHeadPosition();
	for( int nHwndIdx = 0; nHwndIdx < _list.GetCount(); nHwndIdx++ )
	{
		HWND hWndHooked = _list.GetNext( pos );
		VERIFY( SetupHookWndSink( hWndHooked, false ) );
	} // for( int nHwndIdx = 0; nHwndIdx < _list.GetCount(); nHwndIdx++ )
}

void CExtHookSink::GetHookedWindows( HookedWndList_t & _list )
{
	_list.RemoveAll();
POSITION posChains = g_HookChainsMap.GetStartPosition();
	for( ; posChains != NULL; )
	{
		CExtHookSink::HookChains_t * pHookChains = NULL;
		HWND hWndHooked = NULL;
		g_HookChainsMap.GetNextAssoc(
			posChains, hWndHooked, pHookChains );
		ASSERT( hWndHooked != NULL );
		ASSERT( pHookChains != NULL );
		ASSERT( pHookChains->m_hWndHooked == hWndHooked );
		if( pHookChains->m_HookSinkArray.Find(this) < 0 )
			continue;
		ASSERT( _list.Find(pHookChains->m_hWndHooked) == NULL );
		_list.AddTail( pHookChains->m_hWndHooked );
	} // for( ; pos != NULL; )
}

bool CExtHookSink::IsHookedWindow( HWND hWnd )
{
CExtHookSink::HookChains_t * pHookChains = NULL;
	if( !g_HookChainsMap.Lookup( hWnd, pHookChains ) )
		return false;
	ASSERT( pHookChains != NULL );
	ASSERT( pHookChains->m_hWndHooked == hWnd );
	if( pHookChains->m_HookSinkArray.Find(this) >= 0 )
		return true;
	return false;
}